package com.ruoyi.extdata.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bizsys.domain.CustomerXdsReport;
import com.ruoyi.bizsys.domain.ExtReqLog;
import com.ruoyi.bizsys.domain.RealNameAuth;
import com.ruoyi.bizsys.service.ICustomerXdsReportService;
import com.ruoyi.bizsys.service.IExtReqLogService;
import com.ruoyi.bizsys.service.IRealNameAuthService;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Func;
import com.ruoyi.common.utils.JAXBUtil;
import com.ruoyi.common.utils.Xml2Json;
import com.ruoyi.extdata.common.config.XdsConfig;
import com.ruoyi.extdata.domain.ConsumerFullCreditReport;
import com.ruoyi.extdata.domain.ConsumerMatch;
import com.ruoyi.extdata.domain.XdsEntity;
import com.ruoyi.extdata.service.IFileService;
import com.ruoyi.extdata.service.IXdsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.ruoyi.extdata.common.Constants.EXT_CREDIT_XDS;
import static org.springframework.http.MediaType.TEXT_XML;

/**
 * @author cyh
 * @Date: 2021/7/26 3:41 下午
 */
@Slf4j
@Service
public class XdsServiceImpl implements IXdsService {


    @Autowired
    private XdsConfig xdsConfig;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private IFileService fileService;

    @Autowired
    private IRealNameAuthService iRealNameAuthService;

    @Autowired
    private ICustomerXdsReportService customerXdsReportService;

    @Autowired
    private IExtReqLogService extReqLogService;


    /**
     * 获取用户征信信息
     *
     * @param consumerMatch
     * @return https://uat.firstcentralcreditbureau.com/FirstCentralNigeriaWebService/FirstCentralNigeriaWebService.asmx?op=ConnectConsumerMatch
     */
    @Override
    public CustomerXdsReport consumerMatch(ConsumerMatch consumerMatch) {

        consumerMatch.setDataTicket(getTicket());
        JSONObject consumerFullCredit = new JSONObject();
        Object responseObj = new Object();
        try {
            XdsEntity consumerMatchEntity = new XdsEntity().consumerMatch(consumerMatch);
            Map<String, Map<String, Map<String, Map<String, Map>>>> responseMap = soapRequest(consumerMatchEntity, xdsConfig.getConsumerMatchUrl(), "Consumer-Match");
            //格式转化
            responseObj = responseMap.get("Envelope").get("Body").get("ConnectConsumerMatchResponse").get("ConnectConsumerMatchResult");
            try {
                consumerFullCredit = (JSONObject) Xml2Json.xml2Json(responseObj.toString()).get("MatchedConsumer");
            } catch (Exception e) {
                log.error("consumerFullCredit XML 转化异常，尝试转JSONArray", e);
                //尝试转JSONArray，
                JSONArray arrayJson = (JSONArray) Xml2Json.xml2Json(responseObj.toString()).get("MatchedConsumer");
                for (Object obj : arrayJson) {
                    JSONObject js = (JSONObject) obj;
                    if (Func.isEmpty(consumerFullCredit.get("MatchingRate"))) {
                        consumerFullCredit.put("MatchingRate", 0);
                    }
                    int matchingRate = Integer.parseInt(js.get("MatchingRate").toString());
                    int resRate = Integer.parseInt(consumerFullCredit.get("MatchingRate").toString());
                    if (matchingRate > resRate) {
                        consumerFullCredit = js;
                    }
                }
            }
            if (Func.isEmpty(consumerFullCredit)) {
                return null;
            }
        } catch (Exception e) {
            log.error("xds数据格式转换异常,{}", responseObj.toString(), e);
            return null;
        }
        return addOrUpdateReport(consumerFullCredit, consumerFullCredit, consumerMatch.getUserId(), 1);
    }


    /**
     * @param consumerFullCreditReport
     * @return https://uat.firstcentralcreditbureau.com/FirstCentralNigeriaWebService/FirstCentralNigeriaWebService.asmx?op=GetConsumerFullCreditReport
     */
    @Override
    public CustomerXdsReport getConsumerFullCreditReport(ConsumerFullCreditReport consumerFullCreditReport) {
        JSONObject consumerFullCredit = null;
        try {
            consumerFullCreditReport.setDataTicket(getTicket());
            XdsEntity consumerMatchEntity = new XdsEntity().consumerFullCreditReport(consumerFullCreditReport);
            Map<String, Map<String, Map<String, Map>>> responseMap = soapRequest(consumerMatchEntity, xdsConfig.getFullCreditReportUrl(), "Full-Credit-Report");
            Object responseObj = responseMap.get("Envelope").get("Body").get("GetConsumerFullCreditReportResponse").get("GetConsumerFullCreditReportResult");
            consumerFullCredit = Xml2Json.xml2Json(responseObj.toString());
            if (Func.isEmpty(consumerFullCredit)) {
                return null;
            }
        } catch (Exception e) {
            log.error("xds-FullCreditReport数据格式转换异常", consumerFullCredit == null ? "isNull" : consumerFullCredit.toString(), e);
            return null;
        }

        //保存文件服务器
        //String urlPath = fileService.createJsonFileToServer(consumerFullCredit);
        String path = "xds";
        String urlPath = fileService.createJsonFile(consumerFullCredit, path);
        return addOrUpdateReport(consumerFullCredit, urlPath, consumerFullCreditReport.getCustNo(), 2);
    }

    @Override
    public CustomerXdsReport getConsumerFullCreditReport(String userId, String bvn, String accountNumber) {
        ConsumerMatch consumerMatch = new ConsumerMatch();
        consumerMatch.setUserId(userId);
        consumerMatch.setAccountNumber(accountNumber);
        consumerMatch.setIdentification(bvn);
        consumerMatch.setConsumerName("");
        //实名生日格式：dd-MM-yyyy 转 dd/MM/yyyy
        consumerMatch.setDateOfBirth("");
        consumerMatch.setProductID("50");
        consumerMatch.setEnquiryReason("Credit");

        CustomerXdsReport consumerMatchReport = consumerMatch(consumerMatch);
        if (consumerMatchReport == null || consumerMatchReport.getConsumerId().equals("0")) {
            return null;
        }
        ConsumerFullCreditReport consumerFullCreditReport = new ConsumerFullCreditReport();
        consumerFullCreditReport.setConsumerID(consumerMatchReport.getConsumerId());
        consumerFullCreditReport.setCustNo(consumerMatchReport.getUserId());
        consumerFullCreditReport.setEnquiryID(consumerMatchReport.getEnquiryId());
        consumerFullCreditReport.setSubscriberEnquiryEngineID("");
        consumerFullCreditReport.setConsumerMergeList("");
        return getConsumerFullCreditReport(consumerFullCreditReport);
    }

    /**
     * 获取Ticket
     *
     * @return
     */
    public String getTicket() {
        Object cacheObject = redisCache.getCacheObject(EXT_CREDIT_XDS);
        if (Func.isNotEmpty(cacheObject)) {
            return cacheObject.toString();
        }
        XdsEntity login = new XdsEntity().login(xdsConfig.getUserName(), xdsConfig.getPassword());
        Map<String, Map<String, Map<String, Map<String, String>>>> responseMap = soapRequest(login, xdsConfig.getLoginUrl(), "Get-Ticket");
        String o = responseMap.get("Envelope").get("Body").get("LoginResponse").get("LoginResult");
        log.info("XDS获取ticket:{}", o);
        //ticket 5小时有效  4.5小时刷新一次 60 * 4.5
        redisCache.setCacheObject(EXT_CREDIT_XDS, o, 270, TimeUnit.MINUTES);
        return o;
    }

    /**
     * Ticket是否有效
     *
     * @return
     */
    public boolean isTicketValid() {
        Object ticket = redisCache.getCacheObject(EXT_CREDIT_XDS);
        if (Func.isEmpty(ticket)) {
            return false;
        }
        XdsEntity ticketValid = new XdsEntity().isTicketValid(ticket.toString());
        Map<String, String> resMap = soapRequest(ticketValid, xdsConfig.getTicketValidUrl(), "Ticket-Valid");
        String res = resMap.get("soap:Body");
        return Func.isEmpty(res) ? false : Boolean.parseBoolean(res);
    }


    /**
     * xds请求
     *
     * @param xdsEntity
     * @param url
     * @return
     */
    @Override
    public Map soapRequest(XdsEntity xdsEntity, String url, String apiName) {
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(TEXT_XML);
        String xmlStr = JAXBUtil.convertToXml(xdsEntity);
        HttpEntity entity = new HttpEntity<>(xmlStr, httpHeaders);
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(180000);
        factory.setReadTimeout(180000);
        RestTemplate restTemplate = new RestTemplate(factory);

        ExtReqLog extReqLog = new ExtReqLog();
        extReqLog.setApiName(apiName);
        extReqLog.setReqUrl(url);
        extReqLog.setReqParam(xmlStr);
        extReqLog.setReqTime(DateUtils.dateTimeNow());

        int reentryNum = 3;
        Map<String, Object> resMap = new HashMap<>();
        while (reentryNum > 0) {
            try {
                log.info("开始请求：" + apiName);
                ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
                String responseString = response.getBody();

                if (apiName.equals("Consumer-Match")) {

                    if (responseString.contains("Invalid Ticket")) {
                        redisCache.deleteObject(EXT_CREDIT_XDS);

                        String tocket = getTicket();
                        xdsEntity = xdsEntity.replaceTicket(tocket);

                        xmlStr = JAXBUtil.convertToXml(xdsEntity);
                        entity = new HttpEntity<>(xmlStr, httpHeaders);
                        extReqLog.setReqParam(xmlStr);

                        log.info("xds令牌失效，重新请求，param-url:{},param-xml:{}，body:{}", url, entity.getBody());
                        reentryNum--;
                        extReqLog.setCallStatus("2");
                        extReqLog.setRetMsg(responseString);
                    } else if (responseString.contains("Timeout")) {
                        log.info("xdsTimeout，重新请求，param-url:{},param-xml:{}，body:{}", url, entity.getBody());
                        reentryNum--;
                        extReqLog.setCallStatus("2");
                        extReqLog.setRetMsg(responseString);
                    } else {
                        reentryNum = 0;
                        log.info("xds请求成功，param-url:{},param-xml:{}，body:{}", url, entity.getBody());
                        extReqLog.setRspResult(responseString);
                        extReqLog.setCallStatus("1");
                        resMap = JAXBUtil.nodesXmlToMap(responseString);
                    }
                } else if (apiName.equals("Full-Credit-Report")) {
                    reentryNum = 0;
                    log.info("xds请求成功，param-url:{},param-xml:{}，body:{}", url, entity.getBody(), responseString);
                    extReqLog.setCallStatus("1");
                    //超出字段长度
                    //extReqLog.setRspResult(responseString);
                    resMap = JAXBUtil.nodesXmlToMap(responseString);
                } else {
                    reentryNum = 0;
                    log.info("xds请求成功，param-url:{},param-xml:{}，body:{}", url, entity.getBody());
                    extReqLog.setCallStatus("1");
                    resMap = JAXBUtil.nodesXmlToMap(responseString);
                }

            } catch (ResourceAccessException e) {
                reentryNum--;
                extReqLog.setCallStatus("2");
                extReqLog.setRetMsg(e.getMessage());
                log.error("{}请求超时，还剩{}次", url, reentryNum);
            } catch (Exception e) {
                reentryNum = 0;
                log.error("{}请求异常", url, e);
                extReqLog.setCallStatus("2");
                extReqLog.setRetMsg(e.getMessage());
                throw new BusinessException(e.getMessage(), RspEnmu.NETWORK_BUSY);
            } finally {
                extReqLogService.insertExtReqLog(extReqLog);
            }
        }
        return resMap;

    }


    /**
     * 新增或修改
     *
     * @param map
     * @param userId
     * @param type   1:匹配结果  2：xds报告
     * @Param source
     */
    private CustomerXdsReport addOrUpdateReport(JSONObject map, Object source, String userId, int type) {

        CustomerXdsReport customerXdsReport = new CustomerXdsReport();

        Field[] fields = CustomerXdsReport.class.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            try {
                String attributeName = fields[i].getName();
                //由于map字段首字母都是大写 比较前转属性名首字母大写
                Set<String> mapKey = map.keySet();
                for (String key : mapKey) {
                    if (key.toUpperCase().equals(attributeName.toUpperCase())) {
                        String methodName = attributeName.substring(0, 1).toUpperCase() + attributeName.substring(1);
                        Method setMethod = CustomerXdsReport.class.getMethod("set" + methodName, String.class);
                        setMethod.invoke(customerXdsReport, map.get(key).toString());
                        continue;
                    }
                }
            } catch (Exception e) {
                log.error("addOrUpdateReport 异常", e);
            }
        }
        customerXdsReport.setUserId(userId);

        RealNameAuth realNameAuth = new RealNameAuth();
        realNameAuth.setUserId(userId);
        realNameAuth = iRealNameAuthService.selectRealNameAuthList(realNameAuth).get(0);

        customerXdsReport.setCustNo(realNameAuth.getCustNo());

        if (1 == type) {
            customerXdsReport.setMtachResult(source.toString());
            customerXdsReport.setCreateTime(new Date());
            customerXdsReport.setStatus("0");
            //新增
            customerXdsReportService.insertCustomerXdsReport(customerXdsReport);
        }
        if (2 == type) {
            //更新
            CustomerXdsReport query = new CustomerXdsReport();
            query.setUserId(userId);
            List<CustomerXdsReport> customerXdsReports = customerXdsReportService.selectCustomerXdsReportList(query);
            if (customerXdsReports.size() == 0) {
                return null;
            }
            customerXdsReport.setStatus("1");
            customerXdsReport.setId(customerXdsReports.get(0).getId());
            customerXdsReport.setUpdateTime(new Date());
            //customerXdsReport.setReportResult(source.toString());
            customerXdsReport.setAwsS3Url(source.toString());
            customerXdsReportService.updateCustomerXdsReport(customerXdsReport);
            customerXdsReport.setCreateTime(customerXdsReports.get(0).getCreateTime());
        }
        return customerXdsReport;

    }

}
